package com.test.reader;

import com.test.BeanReference;
import com.test.definition.BeanDefinition;
import com.test.loader.DefaultDocumentLoader;
import com.test.loader.DocumentLoader;
import com.test.registry.BeanDefinitionRegistry;
import com.test.exception.XmlBeanDefinitionStoreException;
import com.test.resource.Resource;
import com.test.resource.ResourceLoader;
import com.test.value.PropertyValue;
import com.test.value.PropertyValues;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.InputStream;
import java.util.List;

/**
 * XML Bean定义读取器
 * 用于解析XML格式的Bean定义文件，并将解析结果注册到BeanDefinitionRegistry中
 */
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader{

    private DocumentLoader documentLoader = new DefaultDocumentLoader();
    private BeanDefinitionDocumentReader beanDefinitionDocumentReader = new DefaultBeanDefinitionDocumentReader();

    /**
     * XML标签和属性常量
     */
    private static final String BEAN_ELEMENT = "bean";
    private static final String PROP_ELEMENT = "property";
    private static final String ID_ATTRIBUTE = "id";
    private static final String NAME_ATTRIBUTE = "name";
    private static final String CLASS_ATTRIBUTE = "class";
    private static final String VALUE_ATTRIBUTE = "value";
    private static final String REF_ATTRIBUTE = "ref";
    private static final String INIT_METHOD_ATTRIBUTE = "init-method";
    private static final String DESTROY_METHOD_ATTRIBUTE = "destroy-method";
    private static final String SCOPE_ATTRIBUTE = "scope";

    /**
     * 构造函数，初始化BeanDefinitionRegistry
     * @param registry Bean定义注册表
     */
    public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
        super(registry);
    }

    /**
     * 构造函数，初始化BeanDefinitionRegistry和ResourceLoader
     * @param registry Bean定义注册表
     * @param resourceLoader 资源加载器
     */
    public XmlBeanDefinitionReader(BeanDefinitionRegistry registry, ResourceLoader resourceLoader) {
        super(registry, resourceLoader);
    }

    /**
     * 加载Bean定义
     * @param resource 资源对象，表示要解析的XML文件
     * @throws Exception 解析过程中遇到的异常
     */
    public void loadBeanDefinitions(Resource resource) throws Exception {
        try(InputStream inputStream = resource.getInputStream()){
            doLoadBeanDefinitions(inputStream, resource);
        }catch (Exception e){
            throw new XmlBeanDefinitionStoreException("解析XML文件失败 [" + resource + "]", e);
        }
    }

    /**
     * 实际进行Bean定义解析的方法，从输入流中读取XML文档并解析其中的bean定义。
     * 将解析后的bean定义注册到BeanDefinitionRegistry中。
     *
     * @param inputStream 输入流，用于读取XML文件内容
     * @throws DocumentException 如果在解析XML文档时发生错误
     */
    protected void doLoadBeanDefinitions(InputStream inputStream, Resource resource) throws DocumentException {
        // 加载文档：通过调用documentLoader的loadDocument方法，将输入流中的数据加载到Document对象中
        Document document = documentLoader.loadDocument(inputStream);

        // 注册Bean定义：使用beanDefinitionDocumentReader的registerBeanDefinitions方法，将加载的Document中的Bean定义注册到注册表中
        beanDefinitionDocumentReader.registerBeanDefinitions(document, getRegistry());

        // 打印加载信息：输出从指定资源中加载Bean定义的信息，以便于日志记录和调试
        System.out.println("从资源 [" + resource + "] 中加载了bean定义");

        // 使用SAXReader读取并解析XML文档
        SAXReader reader = new SAXReader();
        document = reader.read(inputStream);
        Element root = document.getRootElement();

        // 获取XML文档中的所有bean元素
        List<Element> beanElements = root.elements(BEAN_ELEMENT);
        for (Element beanElement : beanElements) {
            // 从bean元素中提取属性值
            String id = beanElement.attributeValue(ID_ATTRIBUTE);
            String name = beanElement.attributeValue(NAME_ATTRIBUTE);
            String className = beanElement.attributeValue(CLASS_ATTRIBUTE);
            String initMethodName = beanElement.attributeValue(INIT_METHOD_ATTRIBUTE);
            String destroyMethodName = beanElement.attributeValue(DESTROY_METHOD_ATTRIBUTE);
            String scope = beanElement.attributeValue(SCOPE_ATTRIBUTE);

            // 根据类名加载Class对象
            Class<?> clazz = null;
            try {
                clazz = Class.forName(className);
            } catch (ClassNotFoundException e) {
                throw new XmlBeanDefinitionStoreException("找不到类 [" + className + "]", e);
            }

            // 确定bean的名称，优先使用id属性，其次使用name属性，若两者均为空则生成默认名称
            String beanName = id != null && !id.isEmpty() ? id : name;
            if (beanName == null || beanName.isEmpty()) {
                beanName = Character.toLowerCase(clazz.getSimpleName().charAt(0)) + clazz.getSimpleName().substring(1);
            }

            // 创建BeanDefinition对象
            BeanDefinition beanDefinition = new BeanDefinition(clazz);

            // 设置初始化方法（如果存在）
            if (initMethodName != null && !initMethodName.isEmpty()) {
                beanDefinition.setInitMethodName(initMethodName);
            }

            // 设置销毁方法（如果存在）
            if (destroyMethodName != null && !destroyMethodName.isEmpty()) {
                beanDefinition.setDestroyMethodName(destroyMethodName);
            }

            // 设置作用域（如果存在）
            if (scope != null && !scope.isEmpty()) {
                beanDefinition.setScope(scope);
            }

            // 解析bean元素中的property子元素
            List<Element> propertyElements = beanElement.elements(PROP_ELEMENT);
            PropertyValues propertyValues = new PropertyValues();
            for (Element propertyElement : propertyElements) {
                // 提取property元素的属性值
                String propertyName = propertyElement.attributeValue(NAME_ATTRIBUTE);
                String propertyValue = propertyElement.attributeValue(VALUE_ATTRIBUTE);
                String propertyRef = propertyElement.attributeValue(REF_ATTRIBUTE);

                // 验证property元素是否包含name属性
                if (propertyName == null || propertyName.isEmpty()) {
                    throw new XmlBeanDefinitionStoreException("Bean的property元素必须指定name属性");
                }

                Object value;
                // 根据value或ref属性确定property的值
                if (propertyValue != null && !propertyValue.isEmpty()) {
                    value = propertyValue;
                } else if (propertyRef != null && !propertyRef.isEmpty()) {
                    value = new BeanReference(propertyRef);
                } else {
                    throw new XmlBeanDefinitionStoreException("Bean的property元素必须指定value或ref属性之一");
                }

                // 创建PropertyValue对象并添加到PropertyValues中
                PropertyValue pv = new PropertyValue(propertyName, value);
                propertyValues.addPropertyValue(pv);
            }
            beanDefinition.setPropertyValues(propertyValues);

            // 将解析后的BeanDefinition注册到BeanDefinitionRegistry中
            getRegistry().registerBeanDefinition(beanName, beanDefinition);
        }
    }

    public void setDocumentLoader(DocumentLoader documentLoader) {
        this.documentLoader = documentLoader;
    }
    public void setBeanDefinitionDocumentReader(BeanDefinitionDocumentReader beanDefinitionDocumentReader) {
        this.beanDefinitionDocumentReader = beanDefinitionDocumentReader;
    }
}
